﻿/*
 
Celerity: Sensory Overload
Copright 2012 by Adam Hill, David Gannon, Thomas Tamblyn & Patrick Ytting
Contact: adam.hill@outlook.com
Website: adamhill.org
Licence: MS-Pl Licence
  
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Celerity.Logic;

namespace Celerity.World
{
    class PlayerShip
    {
        GameLogic logic;

        private Model shipModel;
        private float scale;
        private Matrix initialModelTransform;

        public float angle; // radians
        private float radius;

        private Vector3 position;
        private Vector3 direction;

        //private float rollSpeed; //radians per second
        //private float maxRollSpeed;
        private float rollAngle; //radians
        private float maxRollAngle;

        private float turnVelocity;
        private float maxThrust;
        private float mass;
        private float frictionCoef;
        private float MaxVelocity { get { return this.maxThrust / frictionCoef; } }

        private float chaos;

        Vector3 tunnelCentre;

        public PlayerShip(Model shipModel, GameLogic logic)
        {
            float shipAngleOffset = -1f * CeleritySettings.PlayerShipRotationOffsetInDegrees * (float)Math.PI / 180;
            this.logic = logic;
            this.shipModel = shipModel;
            this.scale = CeleritySettings.PlayerShipScale;
            this.initialModelTransform = Matrix.CreateFromYawPitchRoll(0.0f, shipAngleOffset, 0.0f);
            this.angle = 0.0f;
            this.radius = 8.3f;
            //this.rollSpeed = 0.0f;
            //this.maxRollSpeed = 0.0f;
            this.rollAngle = 0.0f;
            this.maxRollAngle = 10.0f * (float)Math.PI / 180;
            this.mass = 1.0f;
            this.frictionCoef = 8f;
            this.maxThrust = 1000.0f;
        }

        private float AddAngle(float angle, float delta)
        {
            return (angle + delta) % (float)(2 * Math.PI);
        }

        private void CalculateRollAngle()
        {
            this.rollAngle = this.maxRollAngle * (this.turnVelocity / this.MaxVelocity);
        }

        public void Update(GameTime gameTime, Vector3 tunnelCentre, Vector3 direction, float playerJoystick, float chaosFactor)
        {
            this.chaos = chaosFactor;

            UpdateMovement(gameTime, playerJoystick);
            CalculateRollAngle();

            this.tunnelCentre = tunnelCentre;
            this.position = new Vector3(0.0f, this.radius, 0.0f);
            this.position = Vector3.Transform(this.position, Matrix.CreateRotationZ(this.angle));
            this.position += tunnelCentre;

            this.direction = new Vector3(-direction.X, -direction.Y, direction.Z);

        }

        private float TrimAngle(float angle)
        {
            float rads = (float)(2 * Math.PI);
            if (angle > rads) return angle - rads;
            if (angle < 0.0f) return rads - angle;
            return angle;
        }

        public void UpdateMovement(GameTime gameTime, float playerJoystick)
        {
            float thrust = this.maxThrust * playerJoystick;
            float friction = this.turnVelocity * -frictionCoef;

            float acceleration = (thrust + friction) / mass;
            float timeElapsed = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
            float newVelocity = turnVelocity + acceleration * timeElapsed;
            this.angle += (turnVelocity * timeElapsed + 0.5f * (acceleration * (timeElapsed * timeElapsed))) * (float)Math.PI / 180;
            this.angle = this.TrimAngle(this.angle);
            turnVelocity = newVelocity;

        }

        public void Draw(GraphicsDeviceManager device, Matrix World, Matrix View, Matrix Projection)
        {
            if (!logic.DisplayShip)
            {
                return;
            }

            Matrix orientation = this.initialModelTransform * Matrix.CreateFromYawPitchRoll((float)Math.Atan(this.direction.X), (float)Math.Atan(this.direction.Y), angle + (float)Math.PI - this.rollAngle);
            Matrix scaleWorld = Matrix.CreateScale(this.scale) * orientation;
            foreach (ModelMesh mesh in shipModel.Meshes)
            {

                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.LightingEnabled = true;
                    //effect.EnableDefaultLighting();
                    effect.View = View;
                    effect.Projection = Projection;
                    effect.DirectionalLight0.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f);
                    effect.DirectionalLight0.Direction = Vector3.Transform(new Vector3(0.0f, 1.0f, 0.0f), Matrix.CreateRotationZ(this.angle));
                    effect.DirectionalLight0.SpecularColor = new Vector3(1.0f, 1.0f, 1.0f);
                    effect.DirectionalLight0.Enabled = true;
                    effect.World = scaleWorld * Matrix.CreateTranslation(this.position);
                }
                mesh.Draw();
            }
        }
    }
}
